package com.sunsy.authserver.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunsy.authserver.beans.dto.*;
import com.sunsy.authserver.beans.po.UserStatus;
import com.sunsy.authserver.beans.po.UserToken;
import com.sunsy.authserver.beans.vo.AdminUserVO;
import com.sunsy.authserver.beans.vo.LoginVo;
import com.sunsy.authserver.beans.vo.UniformUserVO;
import com.sunsy.authserver.dao.*;
import com.sunsy.authserver.beans.po.UniformUser;
import com.sunsy.authserver.enums.ErrorCode;
import com.sunsy.authserver.service.UniformUserService;
import com.sunsy.authserver.util.JwtUtil;
import com.sunsy.authserver.util.MD5;
import com.sunsy.authserver.util.Tools;
import com.sunsy.authserver.wrapper.UniformUserWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * (UniformUser)表服务实现类
 *
 * @author makejava
 * @since 2021-07-20 14:40:39
 */
@Service("uniformUserService")
public class UniformUserServiceImpl extends ServiceImpl<UniformUserDao, UniformUser> implements UniformUserService {

    private RedisOperator redisOperator;
    private UserTokenDao userTokenDao;
    private UserStatusDao userStatusDao;
    private JwtUtil jwtUtil;
    private UserTenantRelationDao utrDao;
    private UserAppRelationDao uarDao;
    private UniformUserWrapper wrapper = UniformUserWrapper.build();

    @Autowired
    public void setUtrDao(UserTenantRelationDao utrDao) {
        this.utrDao = utrDao;
    }

    @Autowired
    public void setUarDao(UserAppRelationDao uarDao) {
        this.uarDao = uarDao;
    }

    @Autowired
    public void setUserStatusDao(UserStatusDao userStatusDao) {
        this.userStatusDao = userStatusDao;
    }

    @Autowired
    public void setJwtUtil(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Autowired
    public void setUserTokenDao(UserTokenDao userTokenDao) {
        this.userTokenDao = userTokenDao;
    }

    @Autowired
    public void setRedisOperator(RedisOperator redisOperator) {
        this.redisOperator = redisOperator;
    }

    @Override
    public LoginVo getUserToken(String code) {
        Long userId = Long.valueOf(redisOperator.get(code));
        redisOperator.del(code);
        if (userId == null) {
            ErrorCode.CODE_EXC.apiExc();
        }
        UserToken userToken = userTokenDao.getByUser(userId);
        if (userToken == null) {
            userToken = new UserToken();
        }
        userToken.setUserId(userId);
        String ut = jwtUtil.createToken(MD5.toMD5(JSON.toJSONString(userToken)));
        userToken.setUserToken(ut);
        int i = userToken.getId() == null ? userTokenDao.insert(userToken) : userTokenDao.updateById(userToken);
        return LoginVo.builder().user_token(userToken.getUserToken()).build();

    }

    @Override
    public UniformUser checkUser(LoginDto dto) {
        UniformUser user = null;
        if (Tools.judgePhone(dto.getLogin_identity())) {
            //手机号
            user = baseMapper.getUserByMobile(dto.getLogin_identity());
        } else if (Tools.judgeEmail(dto.getLogin_identity())) {
            //邮箱
            user = baseMapper.getUserByEmail(dto.getLogin_identity());
        } else {
            //域账号
            user = baseMapper.getUserByDomain(dto.getLogin_identity());
        }
        if (user == null) {
            ErrorCode.USER_NOT_FOUNT.apiExc();
        }
        if (!user.getPassword().equals(MD5.toMD5(dto.getPassword()))) {
            ErrorCode.PASSWORD_EXC.apiExc();
        }
        UserStatus us = userStatusDao.selectById(user.getStatus());
        if (us == null) {
            ErrorCode.USER_STATUS_NOT_FOUNT.apiExc();
        }
        if (!us.getCanLogin()) {
            ErrorCode.USER_STATUS_LOGIN.apiExc(us.getStatusName());
        }
        Date now = new Date();
        if (now.before(user.getExpirationDate())) {
            ErrorCode.USER_STATUS_TIME.apiExc("该用户未到激活时间");
        }
        if (user.getExpirationEnd() != null && now.after(user.getExpirationEnd())) {
            ErrorCode.USER_STATUS_TIME.apiExc("该用户已过期");
        }
        return user;
    }

    @Override
    public UniformUserVO getUserInfo2(String userToken) {
        UniformUserVO userVO = baseMapper.getUserByToken(userToken);
        return userVO;
    }

    @Override
    public boolean register(RegisterDto dto) {
        UniformUser user = baseMapper.getUserByMobile(dto.getMobile());
        if (user != null) {
            ErrorCode.USER_MOBILE_EXIST.apiExc();
        }
        if (StringUtils.isNotBlank(dto.getEmail())) {
            user = baseMapper.getUserByEmail(dto.getEmail());
            if (user != null) {
                ErrorCode.USER_EMAIL_EXIST.apiExc();
            }
        }
        user = new UniformUser();
        user.setMobile(dto.getMobile());
        user.setUsername(dto.getUsername());
        user.setEmail(dto.getEmail());
        user.setPassword(MD5.toMD5(dto.getPassword()));
        user.setOpenId(UUID.randomUUID().toString().toLowerCase().replace("-", ""));
        return save(user);
    }

    @Override
    public IPage<AdminUserVO> getUserList(Page page, UserQueryDto dto) {
        IPage<AdminUserVO> result = baseMapper.getUserList(page, dto);
        if (!CollectionUtils.isEmpty(result.getRecords())) {
            Map<Long, AdminUserVO> map = result.getRecords().stream().collect(Collectors.toMap(AdminUserVO::getId, user -> user));
            QueryWrapper uarWrapper = new QueryWrapper();
            uarWrapper.in("uar.user_id", map.keySet());
            List<Map<String, Object>> uarName = uarDao.getAppNameByUserId(uarWrapper);
            if (!CollectionUtils.isEmpty(uarName)) {
                uarName.stream().forEach(it -> {
                    Long userId = (Long) it.get("user_id");
                    String name = String.valueOf(it.get("app_name"));
                    map.get(userId).setAppName(name);
                });
            }
            List<Map<String, Object>> utrName = utrDao.getTenantNameByUserId(uarWrapper);
            if (!CollectionUtils.isEmpty(utrName)) {
                utrName.stream().forEach(it -> {
                    Long userId = (Long) it.get("user_id");
                    String name = String.valueOf(it.get("name"));
                    map.get(userId).setTenant(name);
                });
            }
        }
        return result;
    }

    @Override
    public boolean adminUpdate(UniformUserDTO dto) {
        UniformUser ori = getById(dto.getId());
        if (ori == null) {
            ErrorCode.USER_NOT_FOUNT.apiExc();
        }
        if (StringUtils.isBlank(ori.getAccount()) && StringUtils.isNotBlank(dto.getAccount())) {
            if (baseMapper.getUserByAccount(dto.getAccount()) == null) {
                ori.setAccount(dto.getAccount());
            } else {
                ErrorCode.USER_STATUS_TIME.apiExc("唯一账号已存在");
            }
        }
        if (StringUtils.isBlank(ori.getDomainAccount()) && StringUtils.isNotBlank(dto.getDomainAccount())) {
            if (baseMapper.getUserByDomain(dto.getDomainAccount()) == null) {
                ori.setDomainAccount(dto.getDomainAccount());
            } else {
                ErrorCode.USER_STATUS_TIME.apiExc("域账号已存在");
            }
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ori.setStatus(dto.getStatus());
        ori.setUsername(dto.getUsername());
        ori.setDept(dto.getDept());
        try {
            ori.setExpirationDate(dto.getExpirationDate() != null ? format.parse(dto.getExpirationDate()) : null);
            ori.setExpirationEnd(dto.getExpirationEnd() != null ? format.parse(dto.getExpirationEnd()) : null);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return updateById(ori);
    }

    @Override
    public Boolean insert(UniformUserDTO dto) {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            UniformUser user = UniformUser.builder()
                    .domainAccount(dto.getDomainAccount())
                    .dept(dto.getDept())
                    .email(dto.getEmail())
                    .mobile(dto.getMobile())
                    .expirationDate(dto.getExpirationDate() != null ? format.parse(dto.getExpirationDate()) : null)
                    .expirationEnd(dto.getExpirationEnd() != null ? format.parse(dto.getExpirationEnd()) : null)
                    .password(MD5.toMD5("Abcd123456"))
                    .status(dto.getStatus())
                    .username(dto.getUsername())
                    .openId(MD5.toMD5(UUID.randomUUID().toString()))
                    .build();
            return checkUserInsert(user);
        } catch (ParseException e) {
            ErrorCode.USER_INSERT_EXC.apiExc("用户添加失败，请重试");
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean userUpdate(UpdateUserDto dto) {
        UpdateWrapper update = new UpdateWrapper<>();
        update.eq("open_id", dto.getOpenId());
        update.set(StringUtils.isNotBlank(dto.getAccount()), "account", dto.getAccount());
        update.set(StringUtils.isNotBlank(dto.getDept()), "dept", dto.getDept());
        update.set(StringUtils.isNotBlank(dto.getEmail()), "email", dto.getEmail());
        update.set(StringUtils.isNotBlank(dto.getSinaId()), "sina_id", dto.getSinaId());
        update.set(StringUtils.isNotBlank(dto.getTencentId()), "tencent_id", dto.getTencentId());
        update.set(StringUtils.isNotBlank(dto.getUsername()), "username", dto.getUsername());
        update.set(StringUtils.isNotBlank(dto.getWechatId()), "wechat_id", dto.getWechatId());
        return update(update);
    }

    @Override
    public boolean forgetPwd(ForgetPwdDto dto) {
//        两种情况，，一种是通过openId修改，，一种是通过手机号验证码修改
        UpdateWrapper updateWrapper = new UpdateWrapper<>();
        if (StringUtils.isNotBlank(dto.getMobile())) {
            if (StringUtils.isBlank(dto.getCode())) {
                ErrorCode.VERTIFI_EXC.apiExc("请输入验证码");
            }
            String code = redisOperator.get(dto.getMobile());
            if (StringUtils.isBlank(code)) {
                ErrorCode.VERTIFI_EXC.apiExc("验证码已过期，请重新获取验证码");
            }
            if (!code.equalsIgnoreCase(dto.getCode())) {
                ErrorCode.VERTIFI_EXC.apiExc("验证码不正确，请重新获取验证码");
            }
            updateWrapper.eq("mobile", dto.getMobile());
        } else {
            if (StringUtils.isBlank(dto.getOpenId())){
                ErrorCode.VERTIFI_EXC.apiExc("openId 丢失，请检查参数");
            }
            updateWrapper.eq("open_id", dto.getOpenId());
        }
        updateWrapper.set("password", MD5.toMD5(dto.getPassword()));
        return update(updateWrapper);
    }

    private boolean checkUserInsert(UniformUser user) {
        UniformUser ori = baseMapper.getUserByInfo(user);
        if (ori != null && !ori.getDeleted()) {
            ErrorCode.USER_INSERT_EXC.apiExc("该用户已存在，请检查手机号，邮箱，域账号");
        }
        if (ori != null && ori.getDeleted()) {//将该用户的删除状态修改为未删除，并将基础信息覆盖
            long id = ori.getId();
            BeanUtils.copyProperties(user, ori);
            ori.setId(id);
            return baseMapper.updateByInsert(ori) > 0;
        }
        return save(user);
    }

}
